#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows;
using System.Collections.ObjectModel;
using System.Windows.Shapes;
using System.Windows.Media;

namespace UTable.Objects.Controls
{
    public class UElementMenuPanel: UCanvas
    {

        private Collection<Path> Lines = new Collection<Path>();

        private Collection<LineSegment> Segments = new Collection<LineSegment>();

        private Collection<PathFigure> Figures = new Collection<PathFigure>();

        internal UElementMenuDirectory Item = null;

        internal Canvas LinesCanvas = null;

        public double Orientation
        {
            get { return (double)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Orientation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(double), typeof(UElementMenuPanel), new UIPropertyMetadata(0.0, new PropertyChangedCallback(OrientationChanged)));


        public double Radius
        {
            get { return (double)GetValue(RadiusProperty); }
            set { SetValue(RadiusProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Radius.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RadiusProperty =
            DependencyProperty.Register("Radius", typeof(double), typeof(UElementMenuPanel), new UIPropertyMetadata(100.0, new PropertyChangedCallback(RaidusChanged)));



        public Point Center
        {
            get { return (Point)GetValue(CenterProperty); }
            set { SetValue(CenterProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Center.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CenterProperty =
            DependencyProperty.Register("Center", typeof(Point), typeof(UElementMenuPanel), new UIPropertyMetadata(new Point(0, 0), new PropertyChangedCallback(CenterChanged)));


        public double Angle
        {
            get { return (double)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(double), typeof(UElementMenuPanel), new UIPropertyMetadata(180.0, new PropertyChangedCallback(AngleChanged)));




        private static void RaidusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is UElementMenuPanel)
                (d as UElementMenuPanel).OnRaidusChanged((double)e.OldValue, (double)e.NewValue);
        }

        internal void OnRaidusChanged(double oldValue, double newValue)
        {
            ArrangeChildren();
        }


        private static void OrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is UElementMenuPanel)
                (d as UElementMenuPanel).OnOrientationChanged((double)e.OldValue, (double)e.NewValue);
        }

        internal void OnOrientationChanged(double oldValue, double newValue)
        {
            ArrangeChildren();
        }

        private static void CenterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is UElementMenuPanel)
                (d as UElementMenuPanel).OnCenterChanged((Point)e.OldValue, (Point)e.NewValue);
        }

        internal void OnCenterChanged(Point oldValue, Point newValue)
        {
            ArrangeChildren();
        }

        private static void AngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is UElementMenuPanel)
                (d as UElementMenuPanel).OnAngleChanged((double)e.OldValue, (double)e.NewValue);
        }

        internal void OnAngleChanged(double oldValue, double newValue)
        {
            ArrangeChildren();
        }

        public UElementMenuPanel(): base()
        {
        }

        protected override void  OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
        {
            base.OnVisualChildrenChanged(visualAdded, visualRemoved);
            if (this.IsLoaded)
            {
                ArrangeChildren();
                if (visualAdded != null && visualAdded is UElementMenuItem)
                {
                    (visualAdded as UElementMenuItem).MenuRoot = Item.MenuRoot;
                    (visualAdded as UElementMenuItem).ParentMenuItem = Item;
                }
            }
        }

        internal void ArrangeChildren()
        {
            if (!IsLoaded || Item == null || Item.Role == UElementMenuItemRole.Item)
                return;

            int count = 0;
			FrameworkElement reference = null;
			for (int i = 0; i < this.Children.Count; i++)
			{
				if (this.Children[i] != null)
				{
					reference = this.Children[i] as FrameworkElement;
					count++;
				}
			}
			if (count == 0)
				return;

            double maxAngle;
            if (count == 1)
                maxAngle = 0;
            else
                maxAngle = Angle / (count /2 * 2);

			double desiredAngle = 2.5 * reference.Width / Radius / Math.PI * 180;
            double angle = desiredAngle < maxAngle ? desiredAngle : maxAngle;

            // calculate the position for each child
			for (int i = 0; i < count; i++)
            {
                if (!(this.Children[i] is UElementMenuItem))
                    return;
                double offset = (i + 1) / 2 * angle;

                int direction = i % 2 == 0 ? 1 : -1;

                double orientation = Orientation + direction * offset;
                if (this.Children[i] is UElementMenuDirectory)
                    (this.Children[i] as UElementMenuDirectory).Orientation = orientation;
                double ox = Math.Cos(orientation / 180 * Math.PI) * Radius;
                double oy = -1 * Math.Sin(orientation / 180 * Math.PI) * Radius;
                double top = Center.Y + oy - (this.Children[i] as UElementMenuItem).Height / 2;
                double left = Center.X + ox - (this.Children[i] as UElementMenuItem).Width / 2;
                Canvas.SetTop(this.Children[i], top);
                Canvas.SetLeft(this.Children[i], left);
                if (!(this.Children[i] as UElementMenuItem).IsLoaded)
                    return;
                (this.Children[i] as UElementMenuItem).pathFigure.StartPoint = new Point(-ox, -oy);
                (this.Children[i] as UElementMenuItem).lineSegment.Point = new Point(0, 0);
                
            }
        }
    }
}
